<template>
  <div class="action-container">
    <el-input
      v-model="query.username"
      placeholder="用户名"
      class="handle-input"
    >
      <template #append>
        <el-button type="primary" @click="handleSearch" icon="Search" />
      </template>
    </el-input>
    <el-button type="primary" @click="handleAdd" icon="Plus">新增</el-button>
  </div>
  <div class="container">
    <el-table :data="tableData" border class="table">
      <el-table-column prop="username" label="用户名"></el-table-column>
      <el-table-column label="头像">
        <template #default="scope">
          <el-image
            class="table__thumb"
            :src="scope.row.avatar"
            :preview-src-list="[scope.row.avatar]"
          >
          </el-image>
        </template>
      </el-table-column>
      <el-table-column prop="email" label="邮箱"></el-table-column>
      <el-table-column prop="mobile" label="联系电话"></el-table-column>
      <el-table-column prop="sex" label="性别">
        <template #default="scope">
          {{
            scope.row.sex === "0" ? "男" : scope.row.sex === "1" ? "女" : "保密"
          }}
        </template>
      </el-table-column>
      <el-table-column label="状态">
        <template #default="scope">
          <el-tag :type="scope.row.status === '1' ? 'success' : 'danger'">
            {{ scope.row.status === "1" ? "有效" : "锁定" }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column
        prop="lastLoginTime"
        label="最近访问时间"
      ></el-table-column>
      <el-table-column prop="createTime" label="创建时间"></el-table-column>
      <el-table-column label="操作" width="180">
        <template #default="scope">
          <el-button
            @click="handleEdit(scope.$index, scope.row)"
            icon="Edit"
            circle
          />
          <el-button
            @click="handleDelete(scope.$index, scope.row)"
            icon="Delete"
            circle
          />
        </template>
      </el-table-column>
    </el-table>
    <div class="pagination">
      <el-pagination
        background
        layout="total, prev, pager, next"
        :current-page="query.pageIndex"
        :page-size="query.pageSize"
        :total="pageTotal"
        @current-change="handlePageChange"
      ></el-pagination>
    </div>
  </div>

  <!-- 编辑弹出框 -->
  <el-dialog :title="title" v-model="editVisible" center @close="cancelEdit">
    <el-form
      :model="row"
      :rules="rules"
      ref="form"
      label-width="100px"
      size="small"
    >
      <el-form-item prop="username" label="用户名">
        <el-input v-model="row.username" placeholder="用户名"></el-input>
      </el-form-item>
      <el-form-item prop="password" label="密码">
        <el-input
          v-model="row.password"
          type="password"
          placeholder="新密码"
        ></el-input>
      </el-form-item>
      <el-form-item prop="email" label="邮箱">
        <el-input v-model="row.email" placeholder="邮箱"></el-input>
      </el-form-item>
      <el-form-item prop="mobile" label="联系电话">
        <el-input
          v-model="row.mobile"
          placeholder="联系电话"
          :disabled="title === '编辑用户'"
        ></el-input>
      </el-form-item>
      <el-form-item prop="status" label="状态">
        <el-switch v-model="row.status" />
      </el-form-item>
      <el-form-item prop="sex" label="性别">
        <el-select v-model="row.sex" placeholder="性别">
          <el-option
            v-for="item in sexOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item prop="avatar" label="头像">
        <el-upload
          class="avatar-uploader"
          :action="uploadUrl"
          :show-file-list="false"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
          :headers="headers"
          name="files"
        >
          <img
            style="width: 100%; height: 100%"
            v-if="row.avatar"
            :src="row.avatar"
            alt="头像"
          />
          <i v-else></i>
        </el-upload>
      </el-form-item>
      <el-form-item prop="description" label="描述">
        <el-input v-model="row.description" placeholder="描述"></el-input>
      </el-form-item>
      <el-form-item prop="roleIds" label="角色">
        <el-select
          v-model="row.roleIds"
          multiple
          filterable
          allow-create
          default-first-option
          placeholder="角色"
        >
          <el-option
            v-for="item in roleOptions"
            :key="item.id"
            :label="item.roleName"
            :value="item.id"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item prop="deptId" label="部门">
        <el-select
          v-model="row.deptId"
          filterable
          allow-create
          default-first-option
          placeholder="部门"
        >
          <el-option
            v-for="item in deptOptions"
            :key="item.id"
            :label="item.deptName"
            :value="item.id"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item prop="deptIds" label="数据权限">
        <el-select
          v-model="row.deptIds"
          multiple
          filterable
          allow-create
          default-first-option
          placeholder="数据权限"
        >
          <el-option
            v-for="item in deptOptions"
            :key="item.id"
            :label="item.deptName"
            :value="item.id"
          >
          </el-option>
        </el-select>
      </el-form-item>
    </el-form>
    <template #footer>
      <span>
        <el-button @click="cancelEdit">取 消</el-button>
        <el-button type="primary" @click="saveEdit">确 定</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup>
import { ElMessage, ElMessageBox } from "element-plus";
import { addUser, deleteUser, listUser, updateUser } from "@/api/user";
import { listRole } from "@/api/role";
import { listDept } from "@/api/dept";
import db from "@/utils/db";
import { reactive, ref } from "vue";

const rules = {
  username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
  email: [{ required: true, message: "请输入邮箱", trigger: "blur" }],
  mobile: [{ required: true, message: "请输入联系电话", trigger: "blur" }],
  avatar: [{ required: true, message: "请上传头像", trigger: "blur" }],
  description: [{ required: true, message: "请输入描述", trigger: "blur" }],
  roleIds: [{ required: true, message: "请选择角色", trigger: "blur" }],
  deptId: [{ required: true, message: "请选择部门", trigger: "blur" }],
  deptIds: [{ required: true, message: "请选择数据权限", trigger: "blur" }],
};

const query = reactive({
  username: "",
  pageNum: 1,
  pageSize: 10,
});

const tableData = ref([]);
const pageTotal = ref(0);
const title = ref("");
const editVisible = ref(false);
let row = reactive({});
const form = ref(null);
const sexOptions = [
  {
    value: "0",
    label: "男",
  },
  {
    value: "1",
    label: "女",
  },
  {
    value: "2",
    label: "保密",
  },
];
const uploadUrl = "/api/file";
const headers = {
  Authorization: `Bearer ${db.get("token")}`,
};
const roleOptions = ref([]);
const deptOptions = ref([]);

// 获取用户列表
const queryUser = () => {
  listUser(query).then((res) => {
    tableData.value = res.data.rows;
    pageTotal.value = res.data.total;
  });
};

// 获取角色和部门列表
const queryRoleAndDeptOptions = () => {
  listRole().then((res) => {
    roleOptions.value = res.data.rows;
  });

  listDept().then((res) => {
    deptOptions.value = deptTreeDataToArr(res.data.rows);
  });
};

// 查询操作
const handleSearch = () => {
  query.pageIndex = 1;
  queryUser();
};

// 分页导航
const handlePageChange = (val) => {
  query.pageIndex = val;
  queryUser();
};

// 删除操作
const handleDelete = (index, row) => {
  // 二次确认删除
  ElMessageBox.confirm("确定要删除吗？", "提示", {
    type: "warning",
    confirmButtonText: "确定",
    cancelButtonText: "取消",
  }).then(() => {
    deleteUser(row.id).then(() => {
      ElMessage.success("删除成功");
      queryUser();
    });
  });
};

// 头像上传成功回调
const handleAvatarSuccess = (res) => {
  row.avatar = res.data[0].url;
};

// 上传文件
const beforeAvatarUpload = (file) => {
  const isJPG = file.type === "image/jpeg";
  const isLt2M = file.size / 1024 / 1024 < 2;

  if (!isJPG) {
    ElMessage.error("请上传图片");
  }
  if (!isLt2M) {
    ElMessage.error("上传的图片大小不能超过2M");
  }
  return isJPG && isLt2M;
};

// 显示添加窗口
const handleAdd = () => {
  row = reactive({});

  title.value = "添加用户";
  editVisible.value = true;
};

// 显示编辑窗口
const handleEdit = (index, row) => {
  title.value = "编辑用户";
  this.row = row;
  Object.keys(row).forEach((key) => {
    if (key === "status") {
      this.row[key] = row[key] === "1";
    } else {
      this.row[key] = row[key];
    }
  });

  row.password = "";
  editVisible.value = true;
};

// 取消修改
const cancelEdit = () => {
  editVisible.value = false;
  queryUser();
};

// 保存编辑
const saveEdit = () => {
  form.value.validate((valid) => {
    if (valid) {
      // 处理状态
      row.status = row.status === true ? "1" : "0";

      if (title.value === "编辑用户") {
        updateUser(row).then(() => {
          editVisible.value = false;
          ElMessage.success("更新成功");
          queryUser();
        });
      } else {
        addUser(row).then(() => {
          editVisible.value = false;
          ElMessage.success("添加成功");
          queryUser();
        });
      }
    }
  });
};

// 部门树转数组
const deptTreeDataToArr = (data, id) => {
  const res = [];

  function dfs(tree) {
    const newTree = {
      id: tree.id,
      deptName: tree.deptName,
      parentId: tree.parentId,
    };
    res.push(newTree);
    if (tree.children) {
      for (const item of tree.children) {
        if (item.id === id) {
          break;
        }

        dfs(item);
      }
    }
  }

  for (const item of data) {
    if (item.id !== id) {
      dfs(item);
    }
  }
  return res;
};

queryUser();
queryRoleAndDeptOptions();
</script>

<style lang="scss" scoped>
.handle-input {
  float: right;
  width: 300px;
}

.table {
  &__thumb {
    display: block;
    margin: auto;
    width: 40px;
    height: 40px;
  }
}
</style>
